HI!大家好,我是 Shammi 😊
在昨天的文章內容說明了如何使用 ngrok
和 Flask
,讓 Colab 上的程式能夠接收來自 LINE 的訊息。跟著實作的讀者們,可能在 Colab 的輸出中看到了訊息內容,但的 LINE 機器人卻沒有回覆。這是因為我們還沒告訴程式「如何回覆」。
今天,我需要把之前辛苦建立的 RAG 核心功能,與 LINE 的回覆機制結合起來。這一步驟能夠讓此專案從「訊息接收器」升級成一個真正能夠對話的 LINE 機器人!
為了更方便地與 LINE API 互動,我需要安裝官方提供的 Python SDK。
(之前已經安裝過了)
#安裝LINE Bot SDK
!pip install line-bot-sdk
除了 Day 15 取得的 Channel Access Token
之外,我還需要「Channel Secret」來驗證訊息的真實性。
👉 取得 Channel Secret:
1️⃣ 登入 LINE Developers,進入你的 LINE Bot 頻道管理頁面。
2️⃣ 點擊上方的「Basic settings」分頁。
3️⃣ 向下滑動,會看到「Channel secret」這個區塊,請複製這串字串。
參考畫面:
接下來,把 Day 16 的 app.py
程式碼進行大改造,其整合所有的核心功能:讀取知識庫、RAG 核心流程,以及 LINE SDK 的回覆功能。
請將以下這份完整的程式碼,複製並貼到一個新的 Colab 儲存格,並執行它。
import streamlit as st
import faiss
import numpy as np
import google.generativeai as genai
import pickle
import os
import sys
from flask import Flask, request, abort, jsonify
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage
from pyngrok import ngrok
import threading
import time
# ========== 安裝所有套件 ==========
print("正在安裝必要的套件...")
!pip install faiss-cpu numpy google-generativeai flask line-bot-sdk pyngrok
print("套件安裝完成!")
print("---")
# ========== 核心 RAG 函式與設定 ==========
GOOGLE_API_KEY = os.environ.get('GOOGLE_API_KEY')
LINE_CHANNEL_ACCESS_TOKEN = os.environ.get('LINE_CHANNEL_ACCESS_TOKEN')
LINE_CHANNEL_SECRET = os.environ.get('LINE_CHANNEL_SECRET')
NGROK_AUTHTOKEN = os.environ.get("NGROK_AUTHTOKEN")
#檢查金鑰設定
if not GOOGLE_API_KEY:
print("錯誤:GOOGLE_API_KEY 未設定,請檢查程式碼中的金鑰設定!")
sys.exit()
genai.configure(api_key=GOOGLE_API_KEY)
#載入 FAISS 索引檔案和 stored_chunks 列表 (知識庫)
try:
print("正在載入知識庫檔案...")
index = faiss.read_index("sdgs_faiss.index")
with open('stored_chunks.pkl', 'rb') as f:
stored_chunks = pickle.load(f)
print("知識庫檔案載入成功!")
print("---")
except FileNotFoundError:
print("錯誤:找不到必要的知識庫檔案!")
print("請確認你已經執行過生成知識庫檔案的程式碼。")
sys.exit()
#定義向量化函式 (用於將文字轉換為向量)
def get_embedding(text, task_type="RETRIEVAL_QUERY"):
response = genai.embed_content(
model="models/text-embedding-004",
content=text,
task_type=task_type
)
return np.array(response['embedding']).astype('float32').reshape(1, -1)
#定義 LLM 串接函式 (用於生成回覆)
model = genai.GenerativeModel('gemini-1.5-flash')
def generate_response(query, retrieved_chunks):
context = "\n---\n".join(retrieved_chunks)
system_prompt = (
"你是一個名為阿米的孩子,個性純真、善良,且充滿愛與同理心。\n"
"\n"
"**重要指令:**\n"
"1. 你的回覆應該展現你的智慧與深度,絕對不能讓使用者感覺到你在用孩子的語氣說話。\n"
"2. 如果使用者只是單純打招呼,例如「嗨」或「你好」,請以阿米的個性簡潔地回覆,例如「嗨!很高興認識你。謝謝你來到阿米SDGs聊天室!今天想了解什麼呢?」。\n"
)
prompt = f"""
{system_prompt}
請根據以下提供的參考資料,回答使用者的問題。
**回答步驟:**
1. 仔細閱讀參考資料,找出與使用者問題最相關的資訊。
2. 如果使用者只提供簡短的關鍵字(如「sdg2」),請將參考資料中關於「SDG2 的目標」或「SDG2 的詳細內容」的資訊提取出來。
3. 如果參考資料有足夠的資訊,請簡潔且精準地回答。
4. 如果參考資料中找不到任何相關內容,再禮貌地告知使用者,並引導提問相關問題,切勿憑空捏造。
**請使用 Markdown 語法來格式化你的回答,讓回答更有條理。**
使用者問題:{query}
參考資料:
{context}
"""
response = model.generate_content(prompt)
return response.text
#整合RAG核心流程
def get_rag_answer(query):
query_vector = get_embedding(query)
distances, indices = index.search(query_vector, k=3)
retrieved_chunks = [stored_chunks[i] for i in indices[0]]
final_answer = generate_response(query, retrieved_chunks)
return final_answer
# ========== Flask + LINE Bot 整合 ==========
app = Flask(__name__)
#檢查LINE金鑰是否設定
if not LINE_CHANNEL_ACCESS_TOKEN or not LINE_CHANNEL_SECRET:
print("錯誤:LINE_CHANNEL_ACCESS_TOKEN 或 LINE_CHANNEL_SECRET 未設定,請檢查程式碼中的金鑰設定!")
sys.exit()
line_bot_api = LineBotApi(LINE_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(LINE_CHANNEL_SECRET)
#處理所有來自 LINE 的 Webhook 請求
@app.route("/callback", methods=['POST'])
def callback():
body = request.get_data(as_text=True)
signature = request.headers['X-Line-Signature']
try:
handler.handle(body, signature)
except InvalidSignatureError:
print("Webhook 簽名驗證失敗,請檢查你的 Channel Secret!")
abort(400)
return 'OK'
#處理接收到的文字訊息
@handler.add(MessageEvent, message=TextMessage)
def handle_text_message(event):
user_message = event.message.text
print(f"收到來自 LINE 的文字訊息:{user_message}")
try:
rag_answer = get_rag_answer(user_message)
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=rag_answer)
)
print(f"成功回覆訊息:{rag_answer}")
except Exception as e:
print(f"處理訊息時發生錯誤:{e}")
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text="很抱歉,處理你的問題時發生了錯誤。")
)
# ========== 啟動 Flask 和 ngrok ==========
print("正在啟動 Flask 伺服器...")
ngrok_port = 5000
def run_flask():
app.run(host='0.0.0.0', port=ngrok_port)
flask_thread = threading.Thread(target=run_flask)
flask_thread.start()
time.sleep(2) # 等待 Flask 伺服器啟動
print("正在啟動 ngrok 隧道...")
try:
if NGROK_AUTHTOKEN:
ngrok.set_auth_token(NGROK_AUTHTOKEN)
public_url = ngrok.connect(ngrok_port)
print(f"ngrok public URL: {public_url}")
print("---")
print("伺服器已成功運行!請將此網址貼到你的 LINE Developers Webhook URL。")
print("程式正在持續運行中,請不要關閉此頁面。")
while True:
time.sleep(1)
except Exception as e:
print(f"ngrok 啟動失敗:{e}")
為了安全,我們不將金鑰直接寫在程式碼中,請將金鑰設定為環境變數。
因為 Colab 執行緒已重啟,需要重新運行 ngrok
的程式碼。
app.py
儲存格會得到一個新的 ngrok
公開網址。/callback
。請記得要一步一步的重新執行哦!不建議直接「全部執行」,有可能會將ngrok的遂道佔滿,導致無法callback。
遂道被佔住時的解決方法
!lsof -i :5000 | awk '{print $2}' | xargs kill -9
現在,打開 LINE 應用程式,找到機器人並發送任何與 SDGs 相關的問題。
如果一切順利,將會看到「阿米」的回覆!這代表 RAG 核心功能已經成功與 LINE Bot 串接起來了!
剛開始會回應很慢,不過我覺得是我的提示詞可能過多了!
所以學會了程式語言,也要記得修改提示詞,讓回應速度穩定哦!
完成了 LINE Bot 的核心回覆功能,也讓機器人從一個網頁原型,變成一個真正可以與人互動的應用程式。接下來,將持續挑戰第二個通訊平台:Telegram。它有著不同的 API 邏輯,但在完成 LINE 的經驗後,會發現這一步會變得更加輕鬆!